package assignment;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class MiniApplicationContext {
    //Spring配置文件的路径或文件名
    private final String fileName;
    //一个BeanDefinition的对象表示一个Bean配置
    private BeanDefinition[] beanDefinitions;
    private final Map<String, Object> map = new HashMap<>();

    //构造器,传入的参数为Spring配置文件的文件名
    public MiniApplicationContext(String fileName) {
        this.fileName = fileName;
        parse();
        setMap();
        dependenceInjection();
    }

    public Object getBean(String name) {
        return map.get(name);
    }

    private void setBeanDefinitions(int length) {
//        System.out.println(length);
        beanDefinitions = new BeanDefinition[length];
        for (int i = 0; i < length; i++)
            beanDefinitions[i] = new BeanDefinition();
    }

    private void node(NodeList list) {
        //第一层循环:对于每一个bean
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);
            NodeList childNodes = node.getChildNodes();
            //第二层循环:对于每一个子节点,由于换行也被当作一个子节点,所以初值为1,每次循环递增2
            for (int j = 1; j < childNodes.getLength(); j += 2) {
//                System.out.println("************"+childNodes.item(j).getNodeName()+":"+childNodes.item(j).getNodeValue()+"**********");
//                System.out.println(childNodes.item(j).getAttributes());
//                System.out.println();
                NamedNodeMap attributes = childNodes.item(j).getAttributes();

                beanDefinitions[i].getProperties().put(attributes.item(0).getNodeValue()
                        , attributes.item(1).getNodeValue());
//                    System.out.println(attributes.item(k).getNodeName());
//                    System.out.println(attributes.item(k).getNodeValue());

            }
        }
    }

    private void parse() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        Document document = null;
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.parse("src\\main\\resources\\" + fileName);
        } catch (ParserConfigurationException | IOException | SAXException e) {
            throw new RuntimeException(e);
        }
        NodeList nodeList = document.getElementsByTagName("bean");
        setBeanDefinitions(nodeList.getLength());
        for (int i = 0; i < nodeList.getLength(); i++) {
            NamedNodeMap attributes = nodeList.item(i).getAttributes();
            beanDefinitions[i].setClass_(attributes.item(0).getNodeValue());
            beanDefinitions[i].setId(attributes.item(1).getNodeValue());
//            System.out.println(attributes.getLength());
//            System.out.println(attributes.item(1).getNodeName());
//            System.out.println(attributes.item(1).getNodeValue());
//            System.out.println(nodeList.item(i).getNodeName());
        }
        node(nodeList);
    }

    private void setMap() {
        //根据Bean配置信息
        for (BeanDefinition beanDefinition : beanDefinitions) {
            Object o = null;
            try {
                //使用反射创建类的对象
                Class clazz = Class.forName(beanDefinition.getClass_());
                Constructor constructor = clazz.getConstructor();
                o = constructor.newInstance();
            } catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException |
                     InstantiationException | NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
            //将创建的对象存储在map中
            map.put(beanDefinition.getId(), o);
        }
    }

    private void dependenceInjection() {
        //根据Bean配置信息
        for (BeanDefinition beanDefinition : beanDefinitions) {
            //使用反射,实现Bean属性的依赖注入
            Class clazz = null;
            try {
                clazz = Class.forName(beanDefinition.getClass_());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            for (String next : beanDefinition.getProperties().keySet()) {
                Field declaredField = null;
                try {
                    declaredField = clazz.getDeclaredField(next);
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                }
                declaredField.setAccessible(true);
                try {
                    Object o = map.get(beanDefinition.getId());
                    String s = beanDefinition.getProperties().get(next);
                    try {
                        declaredField.set(o, s);
                    } catch (IllegalArgumentException e) {//如果不是String类型,就转换为int类型
                        int i=Integer.parseInt(s);
                        declaredField.set(o, i);
                    }
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
